import { getDicList } from '@/api/knowledgeTypeAdd/index.js'

import {
  getNodeAndRelationCount,
  getNodeTypeAndAttr,
  addNode,
  getAllNodeAndRelation,
  createNodeRelation,
  downloadKnowledgeGraphTemplate,
  getNodeRelation
} from '@/api/newknowledge/index.js'

import { handleLabel } from '@/utils/index.js'

import TreeSelect from '@/components/TreeSelect'
import G6Editor from '@/views/components/zstp/components/G6Editor'
import { getRandomPosition } from '@/views/components/zstp/utils/index'
import UploadDialog from '../../components/zstp/uploadDialog.vue'
import { mapActions } from 'vuex'
// import vSelectPage from 'v-selectpage';
import { saveAs } from 'file-saver'
import SelectModel from './model/select.vue'
import G6 from '../../../../public/g6/index'

export default {
  components: {
    TreeSelect,
    G6Editor,
    UploadDialog,
    SelectModel
    // vSelectPage
  },
  data() {
    return {
      formInline: {
        sourceId: undefined,
        targetId: undefined,
        relationShipName: undefined
      },
      queryParams: {
        chartType: undefined,
        condition: undefined,
        skip: undefined,
        type: 'node',
        showNum: 50,
        nodeType: ''
      },
      nodeoptions: [],
      labelPosition: 'right',
      formLabelAlign: {
        name: '',
        type: 'node',
        shape: 'circleNode',
        chartType: undefined,
        color: ''
      },
      nodeType: '',
      TreeSelectList: [],
      moreNodeList: [
        {
          label: '节点名称',
          value: ''
        }
      ],
      TypeList: [
        {
          label: '节点',
          value: 'node'
        },
        {
          label: '关系',
          value: 'edge'
        }
      ],
      JumpCountList: [
        {
          value: '1',
          label: '1跳'
        },
        {
          value: '1..2',
          label: '2跳'
        },
        {
          value: '1..3',
          label: '3跳'
        }
      ],
      allNodeData: {},
      popUpObj: {
        state: false
      },
      uploadJsonData: {},
      dialogVisible: false,
      dialogVisible_2: false,
      nodeSelect: [],
      nodeCount: 0,
      edgeCount: 0,
      currentNodeCount: 0,
      currentEdgeCount: 0,
      SameCategoryList: [],
      SameCategory: {},
      addTypeRadioList: [
        {
          value: '1',
          label: '创建类型'
        },
        {
          value: '2',
          label: '选择类型'
        }
      ],
      radioType: '',
      showTable: false,
      activeColor: '',
      loadingFull: null,
      startNodeList: [],
      endNodeList: [],
      sourceName: '',
      targetName: '',
      upperNodeList: [],
      upperRelationship: [],
      upperEdgeList: [],
      nodeSet: new Set()
    }
  },
  watch: {
    dialogVisible_2(val) {
      if (val) {
        // this.getKnowledgeGraph() // 获取开始/结束节点下拉框
      }
    }
  },
  mounted() {
    this.handleGetNodeType()
    this.getDicList()
    this.$bus.$on('getNewData', () => {
      this.handleGetNodeType()
    })
    // 编辑后，重新调用画布初始化方法
    this.$bus.$on('renderCanvas', () => {
      this.queryParams.type = 'node'
      this.queryParams.nodeType = ''
      this.handleGetNodeType()
    })
    // 查询所有的关系
    this.$bus.$on('showNodeRelation', data => {
      // 计算节点和边的数量
      this.currentNodeCount = 0
      this.currentEdgeCount = 0
      getNodeRelation({ nodeId: data.nodeId }).then(res => {
        if (
          res.data.data.node.length === 0 &&
          res.data.data.relationShip.length === 0
        ) {
          this.$message({
            type: 'warning',
            message: '该节点没有关系'
          })
          return
        }

        // 把新的数据，追加在之前的基础上
        res.data.data.node.forEach(item => {
          if (!this.nodeSet.has(item.nodeId)) {
            this.nodeSet.add(item.nodeId)
            this.upperNodeList.push(item)
          }
        })
        res.data.data.relationShip.forEach(item => {
          item.relationShipId = 'edge,' + item.relationShipId
          if (!this.nodeSet.has(item.relationShipId)) {
            this.nodeSet.add(item.relationShipId)
            this.upperEdgeList.push(item)
          }
        })

        // 计算节点和边的数量
        this.currentNodeCount = this.upperNodeList.length
        this.currentEdgeCount = this.upperEdgeList.length

        this.openLoadingAnimate()

        this.handleCanvasData(this.upperNodeList, this.upperEdgeList)
      })
    })
    // 画布加载完成后，关闭遮罩层
    this.$bus.$on('closeLoading', () => {
      this.closeLoadingAnimation()
    })
    // 开启画布加载时的loading
    this.$bus.$on('openLoading', () => {
      this.openLoadingAnimate()
    })
  },
  methods: {
    // 这里存到vuex中，就不再调用两次接口了
    ...mapActions({ setdictlist: 'know/setdictlist' }),
    // 选择后回调
    selectCallback(type, value) {
      if (type == 'sourceId') {
        this.sourceName = value[0].name
        this.formInline.sourceId = value[0].nodeId
      } else {
        this.targetName = value[0].name
        this.formInline.targetId = value[0].nodeId
      }
    },
    // 选择开始/结束节点
    hadnleSelectForce(type) {
      this.$refs.selectRef.openModel(type, this.nodeCount)
    },
    // 关闭loading动画
    closeLoadingAnimation() {
      if (this.loadingFull !== null) {
        this.loadingFull.close()
      }
    },
    // 开启loading动画
    openLoadingAnimate() {
      this.loadingFull = this.$loading({
        lock: true,
        text: '正在加载',
        spinner: 'el-icon-loading',
        background: 'rgba(0,0,0,0.7)'
      })
    },
    // 下拉框搜索
    handlePageChange(value) {
      console.log(value)
    },
    handelSingleValues(data) {
      console.log(data)
    },

    // 下载知识图谱模板
    async downTemplate() {
      const result = await downloadKnowledgeGraphTemplate()
      saveAs(result.data, '知识图谱导入模板.xlsx')
    },

    // 获取关系和节点总数
    getNodeAndRelationCount() {
      getNodeAndRelationCount().then(response => {
        this.nodeCount = response.data.data.nodeTotal
        this.edgeCount = response.data.data.relationShipTotal
      })
    },
    handleRadioChange(value) {
      if (value == 2) {
        this.showTable = false
      } else {
        this.showTable = true
      }
      this.moreNodeList = [
        {
          label: '节点名称',
          value: ''
        }
      ]
      this.nodeType = ''
    },

    /** 删除表格中的单个 */
    handleDelete(no, row) {
      this.moreNodeList.splice(no, 1)
    },

    /** 添加类型 */
    handleAdd() {
      this.moreNodeList.push({
        label: '',
        value: ''
      })
    },

    onReset() {
      this.activeColor = ''
      this.queryParams = {
        chartType: '',
        type: 'node',
        skip: '',
        condition: '',
        showNum: 50,
        nodeType: ''
      }
      this.handleGetNodeType()
    },

    onSubmit() {
      this.handleGetNodeType()
    },

    handleSizeChange(val) {
      console.log(`每页 ${val} 条`)
    },

    handleCurrentChange(val) {
      console.log(`当前页: ${val}`)
    },

    /** 打开节点类型弹窗 */
    handleOpenNodeModal() {
      this.dialogVisible = true
      // this.handleGetNodeType()
    },

    /** 关闭节点类型弹窗 */
    handleCloseNodeModal() {
      this.formLabelAlign = {
        name: '',
        type: 'node',
        shape: 'circleNode',
        chartType: undefined,
        color: ''
      }
      this.moreNodeList = [
        {
          label: '节点名称',
          value: ''
        }
      ]
      this.nodeType = ''
      this.radioType = ''
      this.dialogVisible = false
    },

    handleNodeClick(data) {
      this.activeColor = data.nodeType
      this.queryParams.nodeType = data.nodeType
      this.handleGetNodeType()
    },

    /** 获取选择对象 */
    handleNodeSelect(value) {
      const findItem = this.TreeSelectList.find(item => item.nodeType == value)
      // 错误的json转为正确的
      const resultItem = handleLabel(findItem.propertyStr)
      if (!resultItem.length) return

      const nameIndex = resultItem.findIndex(item => item.label === 'name')
      if (nameIndex !== -1) {
        resultItem.splice(nameIndex, 1)
      }
      this.moreNodeList = [
        {
          label: '节点名称',
          value: ''
        }
      ]

      this.moreNodeList.push(...resultItem)
      this.showTable = true
    },

    /** 获取节点类型 */
    handleGetNodeType() {
      this.openLoadingAnimate()
      getNodeTypeAndAttr().then(res => {
        this.TreeSelectList = res.data.data
        this.$store.dispatch('drawer/setisshowcontext', true)
        this.getKnowledgeGraphAll(this.queryParams)
        this.$bus.$emit('exitImportMode', true)
        // 关闭导入模式
        this.$store.dispatch('drawer/setisupload', false)
      })
    },

    /** 通过字典获取下拉框  */
    getDicList() {
      getDicList({}).then(res => {
        this.nodeSelect = res.data.data
        this.setdictlist(this.nodeSelect)
      })
    },

    isNullOrUndefinedOrEmptyString(value) {
      return value === null || value === undefined || value === ''
    },

    /** 保存节点类型 */
    handleSaveNode() {
      if (!this.nodeType) {
        this.$message({
          message: '请填写节点类型',
          type: 'warning'
        })
        return
      }
      // 先寻找在已有的类型中，是否包含此次新增的节点类型
      const containNodeType = this.TreeSelectList.find(
        item => item.nodeType === this.nodeType
      )
      // 若包含，则不让新增
      if (containNodeType && this.radioType === '1') {
        this.$message({
          message: '节点类型已存在',
          type: 'warning'
        })
        return
      }
      // 单独处理节点名称
      const findNodeName = this.moreNodeList.find(
        item => item.label === '节点名称'
      )
      // 存在，并且值不为空
      if (
        findNodeName &&
        this.isNullOrUndefinedOrEmptyString(findNodeName.value) !== true
      ) {
        findNodeName.label = 'name'
      } else {
        return this.$message.warning('请填写节点名称')
      }

      // 再去处理不是节点名称的数据
      this.moreNodeList.forEach(item => {
        // 如果label没填，就是空字符串
        if (this.isNullOrUndefinedOrEmptyString(item.label)) {
          item.label = ''
        }
        // 如果value没填，就是空字符串
        if (this.isNullOrUndefinedOrEmptyString(item.value)) {
          item.value = ''
        }
      })

      const jsonData = {
        nodes: [
          {
            nodeId: '',
            nodeType: this.nodeType,
            propertyList: this.moreNodeList
          }
        ]
      }
      addNode(jsonData).then(response => {
        if (response.data.code === 200) {
          this.dialogVisible = false
          this.handleGetNodeType()
          // this.getKnowledgeGraph()
          this.formLabelAlign = {
            name: '',
            type: 'node',
            shape: 'circleNode',
            chartType: undefined,
            color: ''
          }
          this.$message.success('操作成功')
        } else {
          this.$message.error('操作失败')
        }
        // 无论是否新增成功，都需要隐藏表格
        this.showTable = false
      })
    },

    /** 关闭节点关系弹窗 */
    handleCloseEdgeModal() {
      this.formInline = {
        sourceId: undefined,
        targetId: undefined,
        relationShipName: undefined
      }
      this.dialogVisible_2 = false
    },

    /** 保存节点关系 */
    handleSaveEdge() {
      if (
        !this.formInline.sourceId ||
        !this.formInline.targetId ||
        !this.formInline.relationShipName
      ) {
        this.$message({
          message: '请填写完整',
          type: 'warning'
        })
        return
      }
      if (this.formInline.sourceId === this.formInline.targetId) {
        this.$message({
          message: '请选择不同的节点',
          type: 'warning'
        })
        return
      }
      createNodeRelation(this.formInline).then(response => {
        if (response.data.code === 200) {
          this.dialogVisible_2 = false
          this.handleGetNodeType()
          // this.getKnowledgeGraph()
          this.formInline = {
            sourceId: undefined,
            targetId: undefined,
            relationShipName: undefined
          }
          // 置空输入框
          this.sourceName = ''
          this.targetName = ''

          this.$message.success('操作成功')
        } else {
          this.$message.error('操作失败')
        }
      })
    },

    // 算出中心点
    getCenterPoint(cw, ch, length) {
      // 画布尺寸
      const canvasWidth = cw
      const canvasHeight = ch
      const numberOfStrips = length

      // 计算每条数据的宽度（这里为了精确分配，可能会有小数部分）
      let stripWidth = canvasWidth / numberOfStrips
      let stripHight = canvasHeight / 2

      // 计算每条数据的宽度（这里为了精确分配，可能会有小数部分）
      // 由于像素是整数，我们需要对宽度进行四舍五入，并重新分配余数以确保总宽度正确
      let totalAllocatedWidth = 0
      let roundedStripWidths = []
      for (let i = 0; i < numberOfStrips; i++) {
        let roundedWidth = Math.round(stripWidth)
        // 如果这是最后一条数据，并且还有余数未分配，则将其加到这条数据的宽度上
        if (
          i === numberOfStrips - 1 &&
          canvasWidth - totalAllocatedWidth > roundedWidth
        ) {
          roundedWidth +=
            canvasWidth -
            totalAllocatedWidth -
            (numberOfStrips - 1) * roundedWidth
        }
        roundedStripWidths.push(roundedWidth)
        totalAllocatedWidth += roundedWidth
      }
      let positionsList = []
      // 输出每条数据的中心点位置
      roundedStripWidths.forEach((width, index) => {
        const startX =
          index === 0
            ? 0
            : roundedStripWidths.slice(0, index).reduce((sum, w) => sum + w, 0)
        const centerX = startX + width / 2
        const centerY = canvasHeight // 由于数据条是水平的，y坐标中心点就是画布高度的一半
        // 将中心点位置添加到数组中
        positionsList.push({
          centerX: centerX,
          centerY: centerY
        })
      })
      return {
        stripWidth: roundedStripWidths,
        stripHight: Math.floor(stripHight)
      }
    },

    /** 计算画布宽度 */
    countCanvasWidth(listTotal) {
      // 假设这是你的条数
      let numberOfBars = listTotal
      // 画布初始宽度
      let baseWidth = 800

      // 每增加10条，宽度增加800
      let additionalWidthPer10Bars = 800

      // 计算额外的宽度增量
      let additionalBars = Math.ceil(numberOfBars / 10) - 1 // 向上取整，然后减去1（因为初始10条不需要额外宽度）
      let additionalWidth = additionalBars * additionalWidthPer10Bars

      // 总宽度
      let totalWidth = baseWidth + additionalWidth
      return totalWidth
    },

    /** 处理同类别 */
    handleSameCategory(array1, array2) {
      // 创建一个空对象来存储匹配的结果
      const matchedObject = {}

      // 遍历第一个数组
      array1.forEach(item1 => {
        // 初始化一个数组来存储第二个数组中匹配的对象（如果不存在则创建）
        if (!matchedObject[item1]) {
          matchedObject[item1] = []
        }
        // 遍历第二个数组
        array2.forEach(item2 => {
          // 如果nodeType一致，则将该对象添加到matchedObject中对应id的数组里
          if (item2.nodeType === item1) {
            matchedObject[item1].push(item2)
          }
        })
      })
      return matchedObject
    },

    /** 获取所有节点信息 */
    getKnowledgeGraphAll() {
      this.upperNodeList.length = 0
      this.upperEdgeList.length = 0
      this.nodeSet.clear()

      getAllNodeAndRelation(this.queryParams).then(res => {
        // 获取节点总数和节点关系数
        this.getNodeAndRelationCount()
        if (
          (res.data.data.node == null && res.data.data.relationShip == null) ||
          (res.data.data.node.length == 0 &&
            res.data.data.relationShip.length == 0)
        ) {
          this.currentNodeCount = 0
          this.$bus.$emit('clearCanvas', true) // 清除画布
          this.$bus.$emit('closeLoading', false) // 没有内容的话，也要关闭遮罩层
        } else {
          // 计算节点和边的数量
          this.currentNodeCount = res.data.data.node.length
          this.currentEdgeCount = res.data.data.relationShip.length

          // 保存一份当前的节点和关系数据
          this.upperNodeList = res.data.data.node
          this.upperEdgeList = res.data.data.relationShip
          // 处理节点
          this.upperNodeList.forEach(item => {
            this.nodeSet.add(item.nodeId)
          })
          // 处理关系
          this.upperEdgeList.forEach(item => {
            item.relationShipId = 'edge,' + item.relationShipId
            this.nodeSet.add(item.relationShipId)
          })
          // 处理所需要的数据
          this.handleCanvasData(this.upperNodeList, this.upperEdgeList)
        }
      })
    },

    /** 处理画布所需要的节点和关系 */
    handleCanvasData(allnode, allrelation) {
      // 对节点类型进行去重
      let setArray = new Set()
      allnode.forEach(item => {
        setArray.add(item.nodeType)
      })
      const formatObj = {
        nodes: allnode,
        edges: allrelation
      }
      // 找到一个类别下的数据
      this.SameCategoryList = []
      this.SameCategory = this.handleSameCategory(setArray, formatObj.nodes)

      const canvasWidth = this.countCanvasWidth(formatObj.nodes.length)
      // 找到平均等分的中心点(按照返回列表类别分类)
      const pageSizeObj = this.getCenterPoint(
        canvasWidth,
        2500,
        this.TreeSelectList.length
      )

      // 把对象的值，变成数组
      this.SameCategoryList = Object.values(this.SameCategory)

      let state = false
      let forWidth = 0,
        forHeight = 0
      // 去计算随机坐标
      this.SameCategoryList.forEach((item, index) => {
        if (index > 0 && state == false) {
          forWidth = pageSizeObj.stripWidth[index]
        }
        if (state) {
          forHeight = pageSizeObj.stripHight
        } else {
          forHeight = 0
        }
        getRandomPosition(
          this,
          item,
          Math.floor(pageSizeObj.stripWidth[0]),
          Math.floor(pageSizeObj.stripHight),
          forWidth,
          forHeight,
          state
        )
        state = !state
      })

      // 处理节点
      let resultNodes = []
      this.SameCategoryList.forEach(item => {
        resultNodes.push(...item)
      })
      let nodesList = []
      resultNodes.forEach(item => {
        nodesList.push({
          ...item,
          label: item.name.slice(0, 7),
          size: ['80'],
          id: item.nodeId,
          color: item.color, // 圆背景颜色
          shape: 'circleNode',
          type: 'node',
          start: null,
          end: null
          // x: Number(item.x),
          // y: Number(item.y)
          // inPoints:[[0,1],[0,-1],[1,0],[-1,0]],
        })
      })

      // 处理节点关系
      let edgesList = []
      formatObj.edges.forEach(item => {
        edgesList.push({
          ...item,
          id: item.relationShipId,
          source: item.sourceId,
          sourceId: item.sourceId,
          target: item.targetId,
          targetId: item.targetId,
          // shape: 'line',
          // shape: 'customArcWithArrow',
          // shape: 'customEdge', // 自定义线
          // 线的样式
          style: {
            stroke: '#b8c3ce',
            lineAppendWidth: 10,
            // startArrow: true,
            endArrow: true
          },
          shape: 'quadratic',
          type: 'quadratic',
          // type: 'line', // 显示箭头
          label: item.relationShipName ? item.relationShipName : '',
          // 必须要有这个字段，不然就不显示线上的文字了
          name: item.relationShipName ? item.relationShipName : '',
          relationShipName: item.relationShipName,
          relationShipId: item.relationShipId,
          curveOffset: 20 // 弧度线偏移量
        })
      })
      this.allNodeData = {
        nodes: nodesList,
        edges: edgesList
      }
    },

    /** 导入文件弹窗打开 */
    importJsonData() {
      this.popUpObj.state = true
    },

    /** 从exportDialog获取上传的json数据  */
    getUploadJson(upJsonData) {
      this.uploadJsonData = upJsonData
      this.handleCanvasData(
        this.uploadJsonData.nodes,
        this.uploadJsonData.edges
      )
    }
  },
  beforeDestroy() {
    this.$bus.$off('getNewData')
    this.$bus.$off('renderCanvas')
    this.$bus.$off('closeLoading')
  }
}
